﻿/*
 用于快速读取和存储注册表值
 支持 int bool string
 支持 内存加密int
 */

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;

namespace Extend.PlayerPrefsValues
{
    [Serializable]
    public abstract class PrefsValue<T>
    {
        [SerializeField]
        protected string _prefsKey;
        [SerializeField]
        protected T _value;

        public PrefsValue(string prefsKey)
        {
            _prefsKey = prefsKey;
        }

        public virtual T GetValue()
        {
            return _value;
        }
        public virtual void SetValue(T value)
        {
            _value = value;
        }
        public override string ToString()
        {
            return GetValue().ToString();
        }
    }

    /// <summary>
    /// 2021/4/21 19:55:17
    /// </summary>
    public class PrefsDateTime : PrefsValue<DateTime>
    {
        public PrefsDateTime(string prefsKey) : base(prefsKey)
        {           
            LoadValue(prefsKey, DateTime.MinValue);
        }

        public PrefsDateTime(string prefsKey, DateTime defaultValue) : base(prefsKey)
        {
            LoadValue(prefsKey, defaultValue);
        }

        private void LoadValue(string prefsKey, DateTime defaultValue)
        {
            if (PlayerPrefs.HasKey(_prefsKey))
            {
                if (!DateTime.TryParse(PlayerPrefs.GetString(_prefsKey), out _value))
                {
                    _value = defaultValue;
                    Debug.LogError("playerprefs value with key [" + prefsKey + "] is not match the type DateTime");
                }
            }
            else
            {
                _value = defaultValue;
            }
        }

        public override void SetValue(DateTime value)
        {
            base.SetValue(value);
            PlayerPrefs.SetString(_prefsKey, value.ToString());
        }

        #region operator
        public static implicit operator DateTime(PrefsDateTime value)
        {
            return value.GetValue();
        }
        #endregion
    }

    public class PrefsString : PrefsValue<string>
    {
        public PrefsString(string prefsKey, string defaultValue = "") : base(prefsKey)
        {
            _value = PlayerPrefs.GetString(_prefsKey, defaultValue);
        }

        public override void SetValue(string value)
        {
            base.SetValue(value);
            PlayerPrefs.SetString(_prefsKey, value);
        }

        #region operator
        public static implicit operator string(PrefsString value)
        {
            return value.GetValue();
        }
        #endregion
    }

    public class PrefsBool : PrefsValue<bool>
    {
        public PrefsBool(string prefsKey, bool defaultValue = false) : base(prefsKey)
        {
            if (!PlayerPrefs.HasKey(_prefsKey))
            {
                _value = defaultValue;
            }
            else
            {
                _value = PlayerPrefs.GetInt(_prefsKey) == 1;
            }
        }

        public override void SetValue(bool value)
        {
            base.SetValue(value);
            PlayerPrefs.SetInt(_prefsKey, value ? 1 : 0);
        }
        #region operator
        public static implicit operator bool(PrefsBool value)
        {
            return value.GetValue();
        }
        #endregion
    }

    public class PrefsFloat : PrefsValue<float>, IFormattable
    {
        public PrefsFloat(string prefsKey, float defaultValue = 0f) : base(prefsKey)
        {
            if (string.IsNullOrEmpty(prefsKey))
            {
                throw new System.Exception("prefsKey must not be null or empty");
            }
            _value = PlayerPrefs.GetFloat(_prefsKey, defaultValue);
        }

        public void ChangeValue(float value)
        {
            SetValue(GetValue() + value);
        }

        public override void SetValue(float value)
        {
            base.SetValue(value);
            PlayerPrefs.SetFloat(_prefsKey, _value);
        }

        #region operator, override
        public static implicit operator float(PrefsFloat value)
        {
            return value.GetValue();
        }
        public static PrefsFloat operator ++(PrefsFloat input)
        {
            return input.Increment(input, 1);
        }
        public static PrefsFloat operator --(PrefsFloat input)
        {
            return input.Increment(input, -1);
        }
        public static float operator +(PrefsFloat input, int value)
        {
            return input.GetValue() + value;
        }
        public static float operator -(PrefsFloat input, int value)
        {
            return input.GetValue() - value;
        }
        private PrefsFloat Increment(PrefsFloat input, int value)
        {
            input.ChangeValue(value);
            return input;
        }
        public string ToString(string format, IFormatProvider formatProvider)
        {
            return GetValue().ToString(format, formatProvider);
        }
        #endregion
    }

    public class PrefsInt : PrefsValue<int>, IFormattable
    {
        public PrefsInt(string prefsKey, int defaultValue = 0) : base(prefsKey)
        {
            if (string.IsNullOrEmpty(prefsKey))
            {
                throw new System.Exception("prefsKey must not be null or empty");
            }
            _value = PlayerPrefs.GetInt(_prefsKey, defaultValue);
        }

        public void ChangeValue(int value)
        {
            SetValue(GetValue() + value);
        }

        public override void SetValue(int value)
        {
            base.SetValue(value);
            PlayerPrefs.SetInt(_prefsKey, _value);
        }

        #region operator, override
        public static implicit operator int(PrefsInt value)
        {
            return value.GetValue();
        }
        public static PrefsInt operator ++(PrefsInt input)
        {
            return input.Increment(input, 1);
        }
        public static PrefsInt operator --(PrefsInt input)
        {
            return input.Increment(input, -1);
        }
        public static int operator +(PrefsInt input, int value)
        {
            return input.GetValue() + value;
        }
        public static int operator -(PrefsInt input, int value)
        {
            return input.GetValue() - value;
        }
        private PrefsInt Increment(PrefsInt input, int value)
        {
            input.ChangeValue(value);
            return input;
        }
        public string ToString(string format, IFormatProvider formatProvider)
        {
            return GetValue().ToString(format, formatProvider);
        }
        #endregion
    }

    public class PrefsCheatInt : PrefsInt
    {
        private int _cryptKey;

        public PrefsCheatInt(string prefsKey, int defaultValue = 0) : base(prefsKey, defaultValue)
        {
            _cryptKey = UnityEngine.Random.Range(0, 10000);
            _value = Encrypt(_value, _cryptKey);
        }

        public override int GetValue()
        {
            return Decrypt(_value, _cryptKey);
        }

        public override void SetValue(int value)
        {
            _value = Encrypt(value, _cryptKey);
            PlayerPrefs.SetInt(_prefsKey, value);
        }

        public static int Encrypt(int value, int key)
        {
            return value ^ key;
        }

        public static int Decrypt(int value, int key)
        {
            return value ^ key;
        }

        #region operator
        public static implicit operator int(PrefsCheatInt value)
        {
            return value.GetValue();
        }
        public static PrefsCheatInt operator ++(PrefsCheatInt input)
        {
            return input.Increment(input, 1);
        }
        public static PrefsCheatInt operator --(PrefsCheatInt input)
        {
            return input.Increment(input, -1);
        }
        public static PrefsCheatInt operator +(PrefsCheatInt input, int value)
        {
            return input.Increment(input, value);
        }
        public static PrefsCheatInt operator -(PrefsCheatInt input, int value)
        {
            return input.Increment(input, -value);
        }
        private PrefsCheatInt Increment(PrefsCheatInt input, int value)
        {
            input.ChangeValue(value);
            return input;
        }
        #endregion
    }

    public static class ValueTestCode
    {
        public static void TestFunc()
        {
            PrefsCheatInt i = new PrefsCheatInt("TestClass 9", 4);
            PrefsCheatInt j = new PrefsCheatInt("TestClass 11", 1);

            if (j >= i)
            {
                Debug.Log("true");
            }
            else
            {
                Debug.Log("false");
            }
            i++;

            Debug.Log(j + " " + i);

            j = j + i;
            Debug.Log(j);
            j += 1;

            Debug.Log(j);

            PrefsBool b0 = new PrefsBool("TestClass b", true);
            if (b0 && j > i)
            {
                Debug.Log("true");
            }
            else
            {
                Debug.Log("false");
            }
            b0.SetValue(j > i);

        }
    }
}
